#pragma once
#include "inetaddr.hpp"
#include "common.hpp"
#include "log.hpp"


class  Socket
{
public:
    virtual ~Socket()
    {
        
    }

    virtual void CreateServerSocket() = 0;
    virtual void CreateClientSocket() = 0;
    virtual void SocketBind(uint16_t port) = 0; 
    virtual void SocketListen() = 0;
    virtual void SocketConnect(std::string ip,uint16_t port) = 0;
    virtual std::shared_ptr<Socket> SocketAccept(InetAddr& client) = 0;
    virtual int Read(std::string& buffer_queue) = 0;
    virtual void Write(const std::string& wstr) = 0;

    void BindTcpServerSocket(uint16_t port)
    {
        CreateServerSocket();
        SocketBind(port);
        SocketListen();
    }

    void BindTcpClientSocket()
    {
        CreateClientSocket();
    }
};


class TcpSocket : public Socket
{
public:
    TcpSocket(int sockfd)
    :_sockfd(sockfd)
    {

    }

    TcpSocket()
    {
        
    }

    ~TcpSocket() override
    {


    }

    void CreateServerSocket() override 
    {
        int sockfd  = ::socket(AF_INET,SOCK_STREAM,0);
        if(sockfd == -1)
        {
            LOG(LogLevel::FATAL) << "socket fail";
            std::exit(static_cast<int>(ExitCode::SOCKET_ERR));
        }
        _sockfd = sockfd;
        LOG(LogLevel::INFO) << "socket success";
    }

    void CreateClientSocket() override
    {
        int sockfd  = ::socket(AF_INET,SOCK_STREAM,0);
        if(sockfd == -1)
        {
            std::cout << "socket fail";
            std::exit(static_cast<int>(ExitCode::SOCKET_ERR));
        }
        _sockfd = sockfd;
        std::cout << "socket success";
    }

    void SocketBind(uint16_t port) override
    {
        InetAddr local(port);
        int n = ::bind(_sockfd,(struct sockaddr*)&local.GetAddr(),local.Getlen());
        if(n == -1)
        {
            LOG(LogLevel::FATAL) << "bind fail";
            std::exit(static_cast<int>(ExitCode::BIND_ERR));
        }
        LOG(LogLevel::INFO) << "bind success";
    }

    void SocketListen() override
    {
        int n = ::listen(_sockfd,8);
        if(n == -1)
        {
            LOG(LogLevel::FATAL) << "listen fail";
            std::exit(static_cast<int>(ExitCode::LISTEN_ERR));
        }
        LOG(LogLevel::INFO) << "listen success";
    }

    void SocketConnect(std::string ip,uint16_t port) override
    {
        InetAddr server(ip,port);
        int n = ::connect(_sockfd,(struct sockaddr*)&server.GetAddr(),server.Getlen());
        if(n == -1)
        {
            std::cout << "conenct fail" << std::endl;
            std::exit(static_cast<int>(ExitCode::CONNECT_ERR));
        }
        std::cout << "connect success" << std::endl;
    }

    std::shared_ptr<Socket> SocketAccept(InetAddr& client) override
    {
        socklen_t len = client.Getlen();
        int fd = ::accept(_sockfd,(struct sockaddr*)&client.GetAddr(),&len);
        if(fd == -1)
        {
            LOG(LogLevel::FATAL) << "accept fail";
            std::exit(static_cast<int>(ExitCode::ACCEPT_ERR));
        }
        client.Ntop();
        LOG(LogLevel::INFO) << "accept success,客户端[" << client.GetIp() << ":" << client.GetPort() << "]";
        return std::make_shared<TcpSocket>(fd);
    }

    int Read(std::string& buffer_queue) override
    {   
        char buffer[1024];
        int n  =  ::recv(_sockfd,buffer,sizeof(buffer)-1,0);
        if(n > 0)
        {
            buffer[n] = 0;
            buffer_queue += buffer;
        }
        return n;
    }

    void Write(const std::string& wstr) override
    {
        ::send(_sockfd,wstr.c_str(),wstr.size(),0);        
    }


private:
    int _sockfd;
};







